using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Data.OleDb;
using System.IO;
using System.Text;
using System.Threading;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Markup;
using System.Windows.Media;
using System.Windows.Shapes;
using System.Windows.Threading;
using GeoVision.Addin.Helpers;
using GeoVision.Addin.Core.Spatial;

namespace GeoVision.Addin.Core.ShapeCore
{
    public enum ShapeFileGeometryType
    {
        UsePathGeometry,
        UseStreamGeometry,
        UseStreamGeometryNotStroked
    }

    public class ShapeDisplay
    {
        private string fileName;
        private GeoShapeList _geoList;
        #region Delegates
        public delegate void ReadNextPrototype(ShapeFileReadInfo info);
        public delegate void DisplayNextPrototype(ShapeFileReadInfo info);
        #endregion Delegates

        #region Constants
        private const int readShapesBlockingFactor = 50;
        private const int displayShapesBlockingFactor = 10;
        #endregion Constants

        #region Private fields
        private Dispatcher dispatcher;

        // Used during reading of a shapefile.
        private bool isReadingShapeFile;
        private bool cancelReadShapeFile;
        private Microsoft.Office.Interop.Visio.Page _page;
        private ShapeFileGeometryType geometryType = ShapeFileGeometryType.UsePathGeometry;

        #endregion Private fields

        private SHPFileVisioGenerator generator;

        #region Constructor
        public ShapeDisplay(SHPFileVisioGenerator generator)
        {
            this.generator = generator;
            this.dispatcher = new Canvas().Dispatcher;
            this._geoList = new GeoShapeList();
            _geoList.DisableMinMaxCalculation = true;
        }
        #endregion Constructor

        #region Properties
        public bool IsReadingShapeFile
        {
            get { return this.isReadingShapeFile; }
        }
        public ShapeFileGeometryType GeometryType
        {
            get { return this.geometryType; }
            set { this.geometryType = value; }
        }
        #endregion Properties

        #region Public methods

        public void ReadShapeFile()
        {
            this.isReadingShapeFile = true;
            this.cancelReadShapeFile = false;

            // Create an object to store shapefile info during the read.
            ShapeFileReadInfo info = new ShapeFileReadInfo();
            info.FileName = fileName;
            info.ShapeFile = new ShapeFile();
            info.Stream = null;
            info.NumberOfBytesRead = 0;
            info.RecordIndex = 0;

            try
            {
                // Read the File Header first.
                info.Stream = new FileStream(generator.FileName, FileMode.Open, FileAccess.Read);
                info.ShapeFile.ReadShapeFileHeader(info.Stream);
                info.NumberOfBytesRead = ShapeFileHeader.Length;

                // Schedule the first read of shape file records using the dispatcher.
                this.dispatcher.BeginInvoke(DispatcherPriority.Normal, new ReadNextPrototype(this.ReadNextShapeRecord), info);
            }
            catch (IOException ex)
            {
                this.EndReadShapeFile(info);
                MessageBox.Show(ex.Message);
            }
        }

        #endregion Public methods
        #region Reading ESRI shapes
        private void ReadNextShapeRecord(ShapeFileReadInfo info)
        {
            if (this.cancelReadShapeFile)
                return;

            try
            {
                // Read a block of shape records.
                for (int i = 0; i < ShapeDisplay.readShapesBlockingFactor; i++)
                {
                    ShapeFileRecord record = info.ShapeFile.ReadShapeFileRecord(info.Stream);
                    info.NumberOfBytesRead += (4 + record.ContentLength) * 2;
                }
            }
            catch (FileFormatException ex)
            {
                this.EndReadShapeFile(info);
                MessageBox.Show(ex.Message);

                return;
            }
            catch (IOException)
            {
                if (info.ShapeFile.Records.Count > 0)
                    this.DisplayShapes(info);
                else
                    this.EndReadShapeFile(info);

                return;
            }
            this.dispatcher.BeginInvoke(DispatcherPriority.Background, new ReadNextPrototype(this.ReadNextShapeRecord), info);
        }
        private void EndReadShapeFile()
        {
            this.isReadingShapeFile = false;
            this.cancelReadShapeFile = true;
        }
        private void EndReadShapeFile(ShapeFileReadInfo info)
        {
            if (info != null && info.Stream != null)
            {
                info.Stream.Close();
                info.Stream.Dispose();
                info.Stream = null;
            }

            this.EndReadShapeFile();
        }
        #endregion Reading ESRI shapes
        private void DisplayShapes(ShapeFileReadInfo info)
        {
            this.dispatcher.BeginInvoke(DispatcherPriority.Normal, new DisplayNextPrototype(this.DisplayNextShapeRecord), info);
        }
        private void DisplayNextShapeRecord(ShapeFileReadInfo info)
        {
            if (this.cancelReadShapeFile)
                return;
            
            foreach (ShapeFileRecord record in info.ShapeFile.Records)
            {
                _geoList.Add(ShapeFileGeoGenerator.ConvertShapeFileRecordToGeoShape(record));
            }
            generator.DrawPolygonsToVisioDoc(info.ShapeFile.FileHeader.XMax, info.ShapeFile.FileHeader.YMax, info.ShapeFile.FileHeader.XMin, info.ShapeFile.FileHeader.YMin, _geoList);
        }
    }
}
// END